#if UNITY_EDITOR
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

/// <summary>
/// 收藏夹窗口：可以保存一些常用的资源或路径，拖拽到"Drag Asssets to Here"区域即可添加，
/// Ctrl + Alt + Q可以聚焦窗口，快捷键1-9可以直接打开对应资源
/// </summary>
public class FavoriteWindow : EditorWindow
{
    [MenuItem("Window/Favorite %&q")]
    static void ShowWindow()
    {
        var window = GetWindow<FavoriteWindow>("Favorite");
        window.Show();
        window.OnEnable();
    }

    /// <summary>
    /// 数据保存路径
    /// </summary>
    private static string k_SaveDataPath => Path.Combine(Application.persistentDataPath, "FavoriteWindowSaveData.bin");

    /// <summary>
    /// 保存的资源列表
    /// </summary>
    public List<Object> assets;

    void OnEnable()
    {
        Load();
    }

    void OnGUI()
    {
        if(assets == null) return;
        
        EditorGUI.BeginChangeCheck();
        
        //绘制资源列表
        for (int i = 0; i < assets.Count; ++i)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label($"{i + 1}:", GUILayout.Width(20));
            assets[i] = EditorGUILayout.ObjectField("", assets[i], typeof(Object), true);
            if (GUILayout.Button("-", GUILayout.Width(20)))
            {
                assets.RemoveAt(i);
                --i;
            }

            GUILayout.EndHorizontal();
        }

        //绘制拖拽区域
        var curEvent = Event.current;
        var dropArea = GUILayoutUtility.GetRect (0.0f, 30.0f, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
        GUI.Box (dropArea, "Drag Assets to Here");
        switch (curEvent.type) {
            case EventType.DragUpdated:
            case EventType.DragPerform:
                if (!dropArea.Contains (curEvent.mousePosition))
                    return;
             
                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
         
                if (curEvent.type == EventType.DragPerform) {
                    DragAndDrop.AcceptDrag ();
             
                    foreach (var asset in DragAndDrop.objectReferences) {
                        assets.Add(asset);
                    }
                    
                    Save();
                }
                break;
        }

        if (EditorGUI.EndChangeCheck())
        {
            Save();
        }
        
        CheckKeyDown();
    }
    
    
    /// <summary>
    /// 快捷键检测
    /// </summary>
    private void CheckKeyDown()
    {
        var cur = Event.current;
        if (cur.type == EventType.KeyDown)
        {
            for (int i = 0; i < 9; ++i)
            {
                if (cur.keyCode == KeyCode.Alpha1 + i)
                {
                    if (i < assets.Count && assets[i] != null)
                    {
                        EditorGUIUtility.PingObject(assets[i]);
                        AssetDatabase.OpenAsset(assets[i]);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 保存数据到本地
    ///  - 以二进制的形式保存在了PersistentPath路径下
    /// </summary>
    private void Save()
    {
        var ms = new MemoryStream();
        using (var bw = new BinaryWriter(ms))
        {
            bw.Write(assets.Count);
            for (int i = 0; i < assets.Count; ++i)
            {
                var assetPath = AssetDatabase.GetAssetPath(assets[i]);
                bw.Write(assetPath != "");
                bw.Write(assetPath != "" ? AssetDatabase.AssetPathToGUID(assetPath) : GetGameObjectPath(assets[i] as GameObject));
            }

            File.WriteAllBytes(k_SaveDataPath, ms.ToArray());
        }
    }

    /// <summary>
    /// 加载数据
    /// </summary>
    private void Load()
    {
        if (assets == null) assets = new List<Object>();
        else assets.Clear();
        
        if (File.Exists(k_SaveDataPath))
        {
            var bytes = File.ReadAllBytes(k_SaveDataPath);
            var ms = new MemoryStream(bytes);
            using (var br = new BinaryReader(ms))
            {
                var cnt = br.ReadInt32();
                for (int i = 0; i < cnt; ++i)
                {
                    var isPrefabObject = br.ReadBoolean();
                    if (isPrefabObject)
                    {
                        var guid = br.ReadString();
                        var assetPath = AssetDatabase.GUIDToAssetPath(guid);
                        var asset = AssetDatabase.LoadAssetAtPath<Object>(assetPath);
                        assets.Add(asset);
                    }
                    else
                    {
                        var scenePath = br.ReadString();
                        var asset = GameObject.Find(scenePath);
                        assets.Add(asset);
                    }
                }
            }
        }
    }

    public string GetGameObjectPath(GameObject obj)
    {
        if (obj == null)
        {
            return "";
        }

        string path = "/" + obj.name;
        while (obj.transform.parent != null)
        {
            obj = obj.transform.parent.gameObject;
            path = "/" + obj.name + path;
        }
        return path;
    }
}
#endif